package com.tuniu.agents.evaluators.common.impl;

import com.tuniu.agents.common.pojo.ChatRecord;
import com.tuniu.agents.common.entity.cart.CartItem;
import com.tuniu.agents.common.entity.cart.FlightCartItem;
import com.tuniu.agents.common.entity.cart.HotelCartItem;
import com.tuniu.agents.common.entity.cart.TrainCartItem;
import com.tuniu.agents.common.entity.favorites.Favorites;
import com.tuniu.agents.common.enums.MessageType;
import com.tuniu.agents.common.message.adaper.AdapterCard;
import com.tuniu.agents.common.service.AntispamService;
import com.tuniu.agents.common.service.ChatRecordService;
import com.tuniu.agents.evaluator.EvaluationResult;
import com.tuniu.agents.evaluators.common.AbstractEvaluator;
import com.tuniu.agents.evaluators.common.EvaluatorProperties;
import com.tuniu.agents.evaluators.common.entity.FavoriteRequest;
import com.tuniu.agents.evaluators.common.entity.FavoriteResponse;
import com.tuniu.agents.impl.evaluator.EvaluatorAgentConfig;
import com.tuniu.agents.util.HttpManager;
import com.tuniu.agents.util.JsonUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Favorites Evaluator
 * Used to evaluate the resource matching degree of favorites
 */
@Component
@Slf4j
public class FavoritesEvaluator extends AbstractEvaluator<Favorites> {

    private static final String NAME = "FAVORITES_EVALUATOR";
    private static final String DESCRIPTION = "Evaluate the resource matching degree of favorites";

    private final EvaluatorProperties properties;

    // API for retrieving favorites list
    private String favoriteUrl;


    @Autowired
    private HttpManager httpManager;

    @Autowired
    private AntispamService antispamService;


    @Autowired
    private ChatRecordService chatRecordServiceImpl; // For retrieving historical data

    public FavoritesEvaluator(EvaluatorProperties properties) {
        super(NAME, DESCRIPTION);
        this.properties = properties;
        favoriteUrl = properties.getFavoriteUrl();
    }


    @Override
    protected EvaluationResult doEvaluate(Favorites target) {
        return null;
    }

    @Override
    protected Flux<String> doEvaluateFlux(Favorites target) {
        if (agent == null) {
            getAgent();
        }

        if (!StringUtils.hasText(target.getItemsString())) {
            return Flux.empty();
        }

        String historyString = String.join(",", target.getConversationHistories());
        String itemsString = target.getItemsString();
        return agent.stream(target.getConversationId(), historyString + "|" + itemsString);
    }

    @Override
    protected Favorites preEvaluate(String conversationId, String queryId) {
        return null;
    }

    @Override
    protected void getAgent() {
        agent = agentManager.getAgent(EvaluatorAgentConfig.FAVORITES_EVALUATOR_AGENT_ID);

    }

    @Override
    protected Favorites preEvaluateByUserId(String userId, String conversationId) {
        Favorites favorites = new Favorites();
        favorites.setConversationId(conversationId);
        log.info("FavoritesEvaluator queryFavorite :conversationId:{},userId:{}", conversationId, userId);
        List<String> traceIds = new ArrayList<>(); // Store conversation IDs
        try {
            // Retrieve favorites data from API
            FavoriteResponse queryFavoriteList = queryFavorite(userId);

            if (queryFavoriteList != null && queryFavoriteList.getData() != null &&
                    queryFavoriteList.getData().getData() != null &&
                    queryFavoriteList.getData().getData().getRows() != null &&
                    !queryFavoriteList.getData().getData().getRows().isEmpty()) {
                List<CartItem> allItems = queryFavoriteList.getData().getData().getRows().stream()
                        .filter(row -> row.getTraceId() != null)
                        .peek(row -> {
                            traceIds.add(row.getTraceId());

                        })
                        .map(row -> {
                            CartItem cartItem = new CartItem();
                            CartItem childItem = convertToCartItem(row);
                            cartItem.setSnapshotId(row.getSnapshotId());
                            cartItem.setResType(row.getResType());
                            cartItem.setStatus(row.getStatus());
                            cartItem.setDepartureCityName(row.getDepartureCityName());
                            cartItem.setArrivalCityName(row.getArrivalCityName());
                            cartItem.setDepartDate(row.getDepartDate());
                            cartItem.setParamType(row.getParamType());
                            cartItem.setUserId(row.getUserId());
                            cartItem.setAddTime(row.getAddTime());
                            cartItem.setParams(childItem);
                            return cartItem;
                        })
                        .collect(Collectors.toList());
                favorites.setItems(allItems);
                List<String> conversationHistories = getConversationHistories(traceIds);
                favorites.setConversationHistories(conversationHistories);
            }

            return favorites;
        } catch (Exception e) {
            log.error("preEvaluate data error! conversationId:{}", conversationId, e);
        }
        return null;
    }

    @Override
    public EvaluationResult evaluate(String conversationId, String queryId) {
        return null;
    }

    @Override
    public EvaluationResult evaluate(String userId) {
        return null;
    }

    @Override
    public boolean supports(Favorites target) {
        return target != null;
    }

    private FavoriteResponse queryFavorite(String userId) {
        FavoriteRequest favoriteRequest = new FavoriteRequest(Long.parseLong(userId));
        return httpManager.post(favoriteUrl, favoriteRequest, FavoriteResponse.class);
    }

    /**
     * Convert different categories of favorites data
     *
     * @param row
     * @return
     */
    private CartItem convertToCartItem(FavoriteResponse.Favorite row) {
        CartItem cartItem = new CartItem();
        try {
            switch (row.getResType()) {
                case 130: // Hotel
                    // Parse hotel parameters
                    cartItem = JsonUtil.fromJson(row.getParams(), HotelCartItem.class);
                    break;
                case 21: // Flight
                    cartItem = JsonUtil.fromJson(row.getParams(), FlightCartItem.class);
                    break;
                case 8: // Train
                    cartItem = JsonUtil.fromJson(row.getParams(), TrainCartItem.class);
                default:
                    break;

            }
        } catch (Exception e) {
            log.error("FavoritesEvaluator convertToCartItem :error:{}", e.getMessage());

        }
        return cartItem;
    }

    /**
     * Get conversation history based on conversation IDs
     *
     * @param traceIds
     * @return
     */
    private List<String> getConversationHistories(List<String> traceIds) {
        List<String> conversationHistories = new ArrayList<>();
        List<ChatRecord> records = chatRecordServiceImpl.findByConversationIdsAndMessageType(traceIds, MessageType.REQUEST.getCode());
        conversationHistories = records.stream()
                .filter(row -> row.getContent() != null && !row.getContent().isEmpty())
                .map(row -> JsonUtil.parseJsonToList(row.getContent(), AdapterCard.class))
                .map(this::handleHistoryConversations)
                .collect(Collectors.toList());
        return conversationHistories;
    }

    private String handleHistoryConversations(List<AdapterCard> adapterCardList) {
        return adapterCardList.stream()
                .map(AdapterCard::getContent)
                .filter(StringUtils::hasText)
                .collect(Collectors.joining(","));
    }

    /**
     * Check evaluation results
     *
     * @param userId
     * @param target
     * @return
     */
    @Override
    protected String checkEvaluateResult(String userId, Favorites target) {
        if (target != null && CollectionUtils.isNotEmpty(target.getItems())) {
            List<Long> snapshotIds = target.getItems().stream().map(item -> {
                if (item != null) {
                    return item.getSnapshotId();
                }
                return null;
            }).collect(Collectors.toList());

            String snapshotIdsMd5 = md5(snapshotIds.toString());
            String snapShotHistory = chatEnvironmentMemory.get(userId, EVALUATOR_IDS) != null ? chatEnvironmentMemory.get(userId, EVALUATOR_IDS).toString() : null; // Historical snapshot ID
            if (snapshotIdsMd5.equals(snapShotHistory)) { // If snapshot hasn't changed, don't evaluate
                String result = JsonUtil.fromJson(chatEnvironmentMemory.get(userId, EVALUATOR_RESULT), String.class);
                if (result != null) {
                    return result;
                }
            } else { // If snapshot ID changes, update it
                chatEnvironmentMemory.add(userId, Map.of(EVALUATOR_IDS, snapshotIdsMd5));
            }
            // Apply MD5 to snapshotIds   

        }
        return null;
    }

}
